package com.iflytek.jzcpx.procuracy.ocr.config;

import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.iflytek.jzcpx.procuracy.common.util.ThreadPoolUtils;
import com.iflytek.jzcpx.procuracy.ocr.common.helper.SwxRequestHelper;
import com.iflytek.jzcpx.procuracy.ocr.common.helper.SwxRequestHelperDecorator;
import com.iflytek.jzcpx.procuracy.tools.cont.ContClient;
import com.iflytek.jzcpx.procuracy.tools.ocr.OcrClient;
import com.iflytek.sxs.dfs.client.FdfsClient;
import org.csource.common.MyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.PropertyResolver;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019-08-07 09:46
 */
@Configuration
@ConditionalOnClass(PropertyResolver.class)
@EnableConfigurationProperties({OcrServerProps.class, ContServerProps.class})
@EnableAsync
@EnableScheduling
public class OcrConfig {
    private static final Logger logger = LoggerFactory.getLogger(OcrConfig.class);

    @Value("${recognize.pool.size:32}")
    private int recognizePoolSize;

    @Value("${ocr.pool.size:32}")
    private int ocrPoolSize;

    @Value("${fastdfs.server.track}")
    private String trackServer;
    
    @Value("${swx.server.ip}")
    private String swx_server_ip;


    @Bean
    @ConditionalOnMissingBean(FdfsClient.class)
    public FdfsClient fdfsClient() throws IOException, MyException {
        FdfsClient fdfsClient = new FdfsClient();
        fdfsClient.setTrackerServer(trackServer);
        fdfsClient.init();
        return fdfsClient;
    }

    @Autowired
    private OcrServerProps ocrProps;

    @Autowired
    private ContServerProps contProps;

    @Bean
    @ConditionalOnMissingBean(OcrClient.class)
    public OcrClient buildOcrClient() {
        // 创建 ocr 客户端
        return new OcrClient(ocrProps.getServer(), ocrProps.getPath(), ocrProps.getCoreSize(), ocrProps.getRetry());
    }

    @Bean
    public ContClient buildContClient() {
        // 创建编目客户端
        return new ContClient(contProps.getServer(), contProps.getPath());
    }

    @Bean
    public SwxRequestHelper buildRequestHelper() {
        return new SwxRequestHelperDecorator(swx_server_ip);
    }

    /**
     * ocr识别并合成线程池
     * @return
     */
    @Bean("ocrComposeExecutor")
    public ThreadPoolExecutor ocrComposeExecutor() {
        return new ThreadPoolExecutor(ocrProps.getCoreSize(), ocrProps.getCoreSize()*2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000),
                new ThreadFactoryBuilder()
                        .setDaemon(false)
                        .setNameFormat("ocrCompose-%d")
                        .setUncaughtExceptionHandler((t, e) -> logger.error("Thread " + t + " failed unexpectedly", e))
                        .build(),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    /**
     * 图像识别批量任务线程池
     *
     * @return
     */
    @Bean("recognizeExecutor")
    public ThreadPoolExecutor recognizeExecutor() {
        return ThreadPoolUtils.createExecutor(recognizePoolSize, "Recognize-Executor");
    }

    /**
     * 图文识别批量任务提交线程池
     * @return
     */
    @Bean("ocrExecutor")
    public ThreadPoolExecutor ocrExecutor() {
        return ThreadPoolUtils.createExecutor(ocrPoolSize, "OCR-Executor");
    }

    /**
     * 批量任务结果推送线程池
     * @return
     */
    @Bean("taskResultPushExecutor")
    public ThreadPoolExecutor taskResultPushExecutor() {
        return ThreadPoolUtils.createExecutor(ocrPoolSize, "TaskResultPush-Executor");
    }

    private ThreadPoolTaskExecutor createExecutor(int poolSize, String threadNamePrefix) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(poolSize);
        executor.setMaxPoolSize(poolSize);
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(90);
        return executor;
    }
}
